home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Panorama / Panorama - Disk 19D (1987-07-22)(Pacific North-West Amigas Club)[WB].zip / Panorama - Disk 19D (1987-07-22)(Pacific North-West Amigas Club)[WB].adf / PipeHandler1.2 / pipesched.c < prev    next >
C/C++ Source or Header  |  1987-06-28  |  11KB  |  400 lines

  1. /****************************************************************************
  2. **  File:       pipesched.c
  3. **  Program:    pipe-handler - an AmigaDOS handler for named pipes
  4. **  Version:    1.1
  5. **  Author:     Ed Puckett      qix@mit-oz
  6. **
  7. **  Copyright 1987 by EpAc Software.  All Rights Reserved.
  8. **
  9. **  History:    05-Jan-87       Original Version (1.0)
  10. **        07-Feb-87    Added "lockct" check in CheckWaiting().
  11. */
  12.  
  13. #include   <libraries/dos.h>
  14. #include   <libraries/dosextens.h>
  15. #include   <libraries/filehandler.h>
  16. #include   <exec/exec.h>
  17.  
  18. #include   "pipelists.h"
  19. #include   "pipename.h"
  20. #include   "pipebuf.h"
  21. #include   "pipecreate.h"
  22. #include   "pipesched.h"
  23. #include   "pipe-handler.h"
  24.  
  25. #if PIPEDIR
  26. # include   "pipedir.h"
  27. #endif PIPEDIR
  28.  
  29. #ifdef DEBUG
  30. # include   "pipedebug.h"
  31. #endif DEBUG
  32.  
  33.  
  34.  
  35. /*---------------------------------------------------------------------------
  36. ** pipesched.c
  37. ** -----------
  38. ** This module handles pipe I/O scheduling.
  39. **
  40. ** Visible Functions
  41. ** -----------------
  42. **    void              StartPipeIO    (pkt, iotype)
  43. **    void              CheckWaiting   (pipe)
  44. **    struct DosPacket  *AllocPacket   (ReplyPort)
  45. **    void              FreePacket     (pkt)
  46. **    void              StartTapIO     (pkt, Type, Arg1, Arg2, Arg3, Handler)
  47. **    void              HandleTapReply (pkt)
  48. **
  49. ** Macros (in pipesched.h)
  50. ** -----------------------
  51. **    - none -
  52. **
  53. ** Local Functions
  54. ** ---------------
  55. **    void  EndPipeIO (pipe, wd)
  56. */
  57.  
  58.  
  59.  
  60. /*---------------------------------------------------------------------------
  61. ** A pipe I/O request is begun.  A WAITINGDATA structure is allocated and
  62. ** the request is stored in it.  It is then stored in the appropriate list
  63. ** (readerlist or writerlist) of the pipe.  Finally, CheckWaiting is called
  64. ** to service requests for that pipe.
  65. **      Notice that CheckWaiting() is only called when a new I/O request
  66. ** comes in, or when the pipe is closed.  At no other time will the state of
  67. ** the pipe change in such a way that more requests for it can be honored.
  68. */
  69.  
  70. void  StartPipeIO (pkt, iotype)
  71.  
  72. struct DosPacket  *pkt;
  73. IOTYPE            iotype;     /* assumed only PIPEREAD or PIPEWRITE */
  74.  
  75. { PIPEKEY      *pipekey;
  76.   PIPEDATA     *pipe;
  77.   WAITINGDATA  *wd;
  78.  
  79.  
  80.   if ((iotype != PIPEREAD) && (iotype != PIPEWRITE))
  81.     { pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN;
  82. SPIOEXIT:
  83.       pkt->dp_Res1= -1;
  84.       ReplyPkt (pkt);
  85.       return;
  86.     }
  87.  
  88.       
  89.   pipekey= (PIPEKEY *) pkt->dp_Arg1;
  90.   pipe= pipekey->pipe;
  91.  
  92.   if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
  93.     { pkt->dp_Res2= ERROR_NO_FREE_STORE;
  94.       goto SPIOEXIT;
  95.     }
  96.  
  97.  
  98.   pkt->dp_Res2= ERROR_INVALID_LOCK;     /* in case not open for iotype */
  99.  
  100.   if (iotype == PIPEREAD)
  101.     { if ((pipekey->iotype != PIPEREAD) && (pipekey->iotype != PIPERW))
  102.         goto SPIOEXIT;
  103.  
  104.       InsertTail (&pipe->readerlist, wd);
  105.     }
  106.   else     /* PIPEWRITE */
  107.     { if ((pipekey->iotype != PIPEWRITE) && (pipekey->iotype != PIPERW))
  108.         goto SPIOEXIT;
  109.  
  110.       InsertTail (&pipe->writerlist, wd);
  111.     }
  112.  
  113.  
  114.   wd->pkt= pkt;
  115.   wd->pktinfo.pipewait.reqtype= iotype;
  116.   wd->pktinfo.pipewait.buf= (BYTE *) pkt->dp_Arg2;     /* buffer */
  117.   wd->pktinfo.pipewait.len= (ULONG)  pkt->dp_Arg3;     /* length */
  118.  
  119.   CheckWaiting (pipe);
  120. }
  121.  
  122.  
  123.  
  124. /*---------------------------------------------------------------------------
  125. ** Read requests for the pipe are satisfied until the pipe is empty or no
  126. ** more requests are left.  Then, write requests are satisifed until the pipe
  127. ** is full or no more requests are left.  This alternating process is
  128. ** repeated until no further changes are possible.
  129. **      Finished requests are sent to EndPipeIO() so that replies may be sent
  130. ** to their owners.  Aftereward, if the pipe is empty and is not open for
  131. ** either read or write, then it is discarded.  If it is open for read, but
  132. ** is empty and has no write requests and is not open for write, then all
  133. ** remaining read requests are returned in their current state.  (This
  134. ** implements EOF.)  A pipe with a positive "lockct" will not be discarded.
  135. ** UnLock() is expected to call here so that a previously locked, empty pipe
  136. ** will be discarded.
  137. */
  138.  
  139. void  CheckWaiting (pipe)
  140.  
  141. PIPEDATA  *pipe;
  142.  
  143. { BYTE         change;
  144.   WAITINGDATA  *wd;
  145.   ULONG        amt;
  146.   void         EndPipeIO();
  147.  
  148.  
  149. #if PIPEDIR
  150.   SetPipeDate (pipe);
  151. #endif PIPEDIR
  152.  
  153.   for (change= TRUE; change; )
  154.     { change= FALSE;
  155.  
  156.       while ( (! (PipebufEmpty (pipe->buf))) &&
  157.               ((wd= (WAITINGDATA *) FirstItem (&pipe->readerlist)) != NULL) )
  158.         { amt= MoveFromPipebuf (pipe->buf, wd->pktinfo.pipewait.buf, wd->pktinfo.pipewait.len);
  159.  
  160.           if (amt)
  161.             { wd->pktinfo.pipewait.buf += amt;
  162.               wd->pktinfo.pipewait.len -= amt;
  163.               change= TRUE;
  164.             }
  165.  
  166.           if (wd->pktinfo.pipewait.len == 0L)     /* then finished with request */
  167.             EndPipeIO (pipe, wd);
  168.         }     /* end of readerlist loop */
  169.  
  170.  
  171.       while ( (! (PipebufFull (pipe->buf))) &&
  172.               ((wd= (WAITINGDATA *) FirstItem (&pipe->writerlist)) != NULL) )
  173.         { amt= MoveToPipebuf (pipe->buf, wd->pktinfo.pipewait.buf, wd->pktinfo.pipewait.len);
  174.  
  175.           if (amt)
  176.             { wd->pktinfo.pipewait.buf += amt;
  177.               wd->pktinfo.pipewait.len -= amt;
  178.               change= TRUE;
  179.             }
  180.  
  181.           if (wd->pktinfo.pipewait.len == 0L)     /* then finished with request */
  182.             EndPipeIO (pipe, wd);
  183.         }     /* end of writerlist loop */
  184.     }
  185.  
  186.  
  187.   if ( PipebufEmpty (pipe->buf)                &&
  188.        (! (pipe->flags & OPEN_FOR_WRITE))      &&
  189.        (FirstItem (&pipe->writerlist) == NULL)    )     /* then EOF */
  190.     { while ((wd= (WAITINGDATA *) FirstItem (&pipe->readerlist)) != NULL)
  191.         EndPipeIO (pipe, wd);
  192.  
  193.       if (! (pipe->flags & OPEN_FOR_READ))     /* readerlist is now empty */
  194. #if PIPEDIR
  195.         if (pipe->lockct == 0)
  196. #endif PIPEDIR
  197.           DiscardPipe (pipe);
  198.     }
  199. }
  200.  
  201.  
  202.  
  203. /*---------------------------------------------------------------------------
  204. ** This routine returns a finished pipe I/O request.  If it is a write
  205. ** request to a pipe with a tap, then the same write request is sent to the
  206. ** tap, and the reply is deferred until HandleTapReply() gets the tap request
  207. ** reply.  (This lets the user stop a pipe by typing a character into a
  208. ** tap window.)
  209. */
  210.  
  211. static void  EndPipeIO (pipe, wd)
  212.  
  213. PIPEDATA     *pipe;
  214. WAITINGDATA  *wd;
  215.  
  216. { struct DosPacket   *pkt, *tappkt;
  217.   struct FileHandle  *taphandle;
  218.  
  219.  
  220.   pkt= wd->pkt;
  221.  
  222.   pkt->dp_Res1= pkt->dp_Arg3 - wd->pktinfo.pipewait.len;
  223.   pkt->dp_Res2= 0;
  224.  
  225.   if (wd->pktinfo.pipewait.reqtype == PIPEREAD)
  226.     { Delete (&pipe->readerlist, wd);
  227.  
  228.       ReplyPkt (pkt);
  229.       FreeMem (wd, sizeof (WAITINGDATA));
  230.     }
  231.   else     /* must be PIPEWRITE -- reqtype is new PIPERW */
  232.     { Delete (&pipe->writerlist, wd);
  233.  
  234.       if (pipe->tapfh != 0)     /* then write to the pipe tap */
  235.         { if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
  236.             { ReplyPkt (pkt);
  237.               FreeMem (wd, sizeof (WAITINGDATA));
  238. #ifdef DEBUG
  239.               OS ("!!! ERROR - Could not allocate packet for tap write\n");
  240. #endif DEBUG
  241.             }
  242.           else
  243.             { wd->pkt= tappkt;     /* reuse wd for tap write request */
  244.               wd->pktinfo.tapwait.clientpkt= pkt;
  245.               /* don't need ...tapwait.handle */
  246.  
  247.               taphandle= (struct FileHandle *) BPTRtoCptr (pipe->tapfh);
  248.  
  249.               StartTapIO ( tappkt, ACTION_WRITE,
  250.                            taphandle->fh_Arg1, pkt->dp_Arg2, pkt->dp_Arg3,
  251.                            taphandle->fh_Type );
  252.  
  253.               InsertHead (&tapwaitlist, wd);     /* for HandleTapReply() */
  254.             }
  255.         }
  256.       else     /* otherwise, return finished packet */
  257.         { ReplyPkt (pkt);
  258.           FreeMem (wd, sizeof (WAITINGDATA));
  259.         }
  260.     }
  261. }
  262.  
  263.  
  264.  
  265. /*---------------------------------------------------------------------------
  266. ** An exec Message and a DosPacket are allocated, and they are initialized.
  267. ** A pointer to the packet is returned, or NULL if it could not be allocated.
  268. */
  269.  
  270. struct DosPacket  *AllocPacket (ReplyPort)
  271.  
  272. struct MsgPort  *ReplyPort;
  273.  
  274. { struct Message    *msg;
  275.   struct DosPacket  *pkt;
  276.  
  277.  
  278.   if ((msg = (struct Message *) AllocMem (sizeof (struct Message), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL)
  279.     return NULL;
  280.  
  281.   if ((pkt = (struct DosPacket *) AllocMem (sizeof (struct DosPacket), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL)
  282.     { FreeMem (msg, sizeof (struct Message));
  283.       return NULL;
  284.     }
  285.  
  286.   msg->mn_Node.ln_Type= NT_MESSAGE;
  287.   msg->mn_Node.ln_Name= (char *) pkt;
  288.  
  289.   msg->mn_ReplyPort= ReplyPort;
  290.  
  291.   pkt->dp_Link= msg;
  292.   pkt->dp_Port= ReplyPort;
  293.  
  294.   return pkt;
  295. }
  296.  
  297.  
  298.  
  299. /*---------------------------------------------------------------------------
  300. ** A DosPacket/exec Message pair is freed.
  301. */
  302.  
  303. void  FreePacket (pkt)
  304.  
  305. struct DosPacket  *pkt;
  306.  
  307. { if (pkt != NULL)
  308.     { if (pkt->dp_Link != NULL)
  309.         FreeMem (pkt->dp_Link, sizeof (struct Message));
  310.  
  311.       FreeMem (pkt, sizeof (struct DosPacket));
  312.     }
  313. }
  314.  
  315.  
  316.  
  317. /*---------------------------------------------------------------------------
  318. ** The indicated fields are filled into the packet and it is sent.
  319. */
  320.  
  321. void  StartTapIO (pkt, Type, Arg1, Arg2, Arg3, Handler)
  322.  
  323. struct DosPacket  *pkt;
  324. LONG              Type;
  325. LONG              Arg1;
  326. LONG              Arg2;
  327. LONG              Arg3;
  328. struct MsgPort    *Handler;
  329.  
  330. { pkt->dp_Type= Type;
  331.   pkt->dp_Arg1= Arg1;
  332.   pkt->dp_Arg2= Arg2;
  333.   pkt->dp_Arg3= Arg3;
  334.  
  335.   PutMsg (Handler, pkt->dp_Link);
  336. }
  337.  
  338.  
  339.  
  340. /*---------------------------------------------------------------------------
  341. ** Handle replies from tap I/O requests.  These were initiated by OpenTap(),
  342. ** CloseTap() and EndPipeIO().
  343. */
  344.  
  345. void  HandleTapReply (pkt)
  346.  
  347. struct DosPacket  *pkt;
  348.  
  349. { WAITINGDATA  *wd;
  350.  
  351.  
  352.   for (wd= (WAITINGDATA *) FirstItem (&tapwaitlist); wd != NULL; wd= (WAITINGDATA *) NextItem (wd))
  353.     if (wd->pkt == pkt)
  354.       { Delete (&tapwaitlist, wd);
  355.         break;
  356.       }
  357.  
  358.   if (wd == NULL)
  359.     {
  360. #ifdef DEBUG
  361.       OS ("!!! ERROR - WAITINGDATA not found in HandleTapReply()\n");
  362. #endif DEBUG
  363.       FreePacket (pkt);
  364.       return;     /* not found - this should never happen */
  365.     }
  366.  
  367.   switch (pkt->dp_Type)
  368.     { case MODE_READWRITE:
  369.       case MODE_READONLY:
  370.       case MODE_NEWFILE:     /* for a tap open request */
  371.              if (pkt->dp_Res1)     /* then successful */
  372.                OpenPipe (wd->pktinfo.tapwait.clientpkt, pkt->dp_Arg1);
  373.              else     /* couldn't open tap */
  374.                { FreeMem (wd->pktinfo.tapwait.handle, sizeof (struct FileHandle));
  375.                  pkt->dp_Res1= 0;
  376.                  pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
  377.                  ReplyPkt (wd->pktinfo.tapwait.clientpkt);
  378.                }
  379.  
  380.              FreeMem (BPTRtoCptr (pkt->dp_Arg3), OPENTAP_STRSIZE);
  381.              break;
  382.  
  383.       case ACTION_END:     /* for a tap close request */
  384.              FreeMem (wd->pktinfo.tapwait.handle, sizeof (struct FileHandle));
  385.              break;
  386.  
  387.       case ACTION_WRITE:     /* for a tap write request */
  388.              ReplyPkt (wd->pktinfo.tapwait.clientpkt);     /* return to client */
  389.              break;
  390.  
  391. #ifdef DEBUG
  392.       default:     /* should never happen */
  393.              OS ("!!! ERROR - bad packet type in HandleTapReply(), type ="); OL (pkt->dp_Type); NL;
  394. #endif DEBUG
  395.     }
  396.  
  397.   FreePacket (pkt);
  398.   FreeMem (wd, sizeof (WAITINGDATA));
  399. }
  400.